#pragma once

#include <ddm/AtomicRoute.h>
#include <openr/common/OpenrEventBase.h>
#include <openr/decision/RibEntry.h>
#include <openr/decision/RouteUpdate.h>
#include <openr/messaging/ReplicateQueue.h>

#include <map>
#include <set>

namespace ddm {

class AtomicFib : public openr::OpenrEventBase {
 public:
  AtomicFib(
      openr::messaging::RQueue<openr::DecisionRouteUpdate> routeUpdatesQueue,
      openr::messaging::ReplicateQueue<AtomicRoute>& atomicRouteUpdatesQueue);
  virtual ~AtomicFib() = default;
  void stop() override;

  void insertRoute(folly::CIDRNetwork prefix, openr::RibUnicastEntry route);
  void deleteRoute(folly::CIDRNetwork prefix);
  void dump();

 private:
  /**
   * Process new route updates
   */
  void processRouteUpdate(openr::DecisionRouteUpdate&& routeUpdate);
  void computeAtomicRouteUpdate();
  // openr::messaging::ReplicateQueue<openr::DecisionRouteUpdate>&
  // routeUpdateQueue_;

  std::set<long>::iterator beupper_bound(long atom);
  std::set<long> atoms_;

  /**
   * Atom to the set of rules that cover the atom, rules are ordered by
   * priority, the rule with highest priority takes action for the atom
   */
  std::map<long, std::map<int, openr::RibUnicastEntry>> atomToRules_;

  // Cache for computing atomic route updates
  std::map<std::string, std::set<long>> egressToAtoms_;

  // Queue to publish atomic route changes
  openr::messaging::ReplicateQueue<AtomicRoute>& atomicRouteUpdatesQueue_;
};

}  // namespace ddm